<template>
  <div
    id="HeatMap"
    ref="chartRef"
    class="no-margin"
    style="height: calc(25vw); max-height: 350px; min-height: 300px"
  ></div>
</template>

<script setup lang="ts">
import {
  onBeforeUnmount,
  onMounted,
  ref,
  Ref,
  computed,
  watch,
  PropType,
} from 'vue';
import { useSiteSettings } from 'src/stores/site_setting';
import { storeToRefs } from 'pinia';

import * as echarts from 'echarts/core';
import {
  TooltipComponent,
  ToolboxComponent,
  GridComponent,
  VisualMapComponent,
} from 'echarts/components';
import { HeatmapChart } from 'echarts/charts';
import { SVGRenderer } from 'echarts/renderers';

import lightTheme from 'src/css/echart_themes/light.json';
import darkTheme from 'src/css/echart_themes/dark.json';

echarts.use([
  TooltipComponent,
  ToolboxComponent,
  GridComponent,
  VisualMapComponent,
  HeatmapChart,
  SVGRenderer,
]);

echarts.registerTheme('myLight', lightTheme);
echarts.registerTheme('myDark', darkTheme);

// 网站的设置状态
const siteSettingStore = useSiteSettings();
const siteSettingRef = storeToRefs(siteSettingStore);

//TODO 定义组件参数
const props = defineProps({
  x_label: {
    type: Array as PropType<string[]>,
    default: () => [],
  },
  y_label: {
    type: Array as PropType<string[]>,
    default: () => [],
  },
  y_title: {
    type: String,
    default: () => 'y',
  },
  phenoType: {
    type: String,
    default: () => 'phenotype',
  },
  data: {
    type: Array as PropType<Array<number>>,
    default: () => [],
  },
  min: {
    type: Number,
    default: () => Number(0),
  },
  max: {
    type: Number,
    default: () => Number(0),
  },
});
const option = computed(() => {
  return {
    tooltip: {
      position: 'top',
      formatter: (param) => {
        return [
          `${props.phenoType}: ` + props.y_label[param.value[1]],
          'Cancer: ' + props.x_label[param.value[0]],
          '-Log10(FDR): ' + param.value[2],
        ].join('<br/>');
      },
    },
    toolbox: {
      show: false,
      top: 0,
      right: 5,
      iconStyle: {
        borderWidth: 2,
      },
      emphasis: {
        iconStyle: {
          borderColor: '#26a69a',
        },
      },
      feature: {
        saveAsImage: {
          type: 'svg',
        },
      },
    },
    grid: {
      top: 20,
      left: 200,
      bottom: 80,
    },
    xAxis: {
      type: 'category',
      data: props.x_label,
      axisLabel: {
        rotate: 90,
        fontSize: 12,
        align: 'right',
        margin: 10,
        interval: 0
      },
      axisLine: {
        show: false
      },
      axisTick: {
        alignWithLabel: true,
      },
      splitArea: {
        show: true,
      },
      name: 'Cancer',
      nameLocation: 'middle',
      nameTextStyle: {
        padding: [50, 0, 0, 0],
        fontSize: 16,
        fontWeight: 'bold',
      },
    },
    yAxis: {
      show: true,
      type: 'category',
      data: props.y_label,
      axisTick: {
        alignWithLabel: true,
      },
      splitArea: {
        show: true,
      },
      axisLine: {
        show: false
      },
      name: props.y_title,
      nameLocation: 'middle',
      nameTextStyle: {
        padding: [0, 0, 160, 0],
        fontSize: 16,
        fontWeight: 'bold',
      },
      axisLabel: {
        fontSize: 12,
        formatter: (value, index) => {
          return value.length > 15 ? value.slice(0, 15) + ' ...' : value;
        },
      },
    },
    visualMap: {
      min: props.min,
      max: props.max,
      type: 'continuous',
      text: ['Max', 'Min'],
      calculable: true,
      realtime: true,
      orient: 'vertical',
      align: 'right',
      top: 'center',
      right: 'right',
      inRange: {
        color: ['#fff7ed', '#f44336'],
      },
    },
    series: [
      {
        name: '-Log(P)',
        type: 'heatmap',
        data: props.data,
        itemStyle: {
          borderType: 'solid',
          borderColor: '#AAA',
        },
        label: {
          show: false,
        },
        emphasis: {
          itemStyle: {
            shadowBlur: 10,
            shadowColor: 'rgba(0, 0, 0, 0.5)',
          },
        },
      },
    ],
  };
});

watch(option, () => {
  chartObj.value = echart_init(chartObj.value, chartRef.value);
});

// 动态切换图的主题
const echart_theme = computed(() => {
  return siteSettingRef.dark.value ? 'myDark' : 'myLight';
});

const echart_init = (
  chartObj?: echarts.ECharts | null,
  chartRef?: HTMLDivElement | null
) => {
  echarts.dispose(chartRef as HTMLDivElement);
  chartObj = echarts.init(chartRef as HTMLDivElement, echart_theme.value, {
    locale: siteSettingRef.language.value,
  });
  chartObj.setOption(option.value);
  return chartObj;
};

const chartObj: Ref<echarts.ECharts | null> = ref(null);
const chartRef = ref<HTMLDivElement>();

watch(siteSettingRef.dark, () => {
  chartObj.value = echart_init(chartObj.value, chartRef.value);
});
watch(siteSettingRef.language, () => {
  chartObj.value = echart_init(chartObj.value, chartRef.value);
});

const resizeHandler = () => {
  chartObj.value?.resize();
};

// 加载图表
onMounted(() => {
  chartObj.value = echart_init(chartObj.value, chartRef.value);
  window.addEventListener('resize', resizeHandler);
});

onBeforeUnmount(() => {
  echarts.dispose(chartRef.value as HTMLDivElement);
  window.removeEventListener('resize', resizeHandler);
});
</script>

<style scoped lang="less"></style>
